Grant tables work on data structures.
3fbba6dbasJQV-MVElDC0DGSHMiL5w tools/libxc/xc_domain.c
40278d99BLsfUv3qxv0I8C1sClZ0ow tools/libxc/xc_elf.h
403e0977Bjsm_e82pwvl9VvaJxh8Gg tools/libxc/xc_evtchn.c
+4227c129ZKjJPNYooHVzBCyinf7Y6Q tools/libxc/xc_gnttab.c
40e03333Eegw8czSWvHsbKxrRZJjRA tools/libxc/xc_io.c
40e03333vrWGbLAhyJjXlqCHaJt7eA tools/libxc/xc_io.h
3fbba6dbNCU7U6nsMYiXzKkp3ztaJg tools/libxc/xc_linux_build.c
* 2. Accessing others' memory reservations via grant references.
* (i.e., mechanisms for both sender and recipient of grant references)
*
+ * Copyright (c) 2005, Christopher Clark
* Copyright (c) 2004, K A Fraser
*/
#include <linux/sched.h>
#include <asm/pgtable.h>
#include <asm/fixmap.h>
+#include <asm/uaccess.h>
+#include <asm-xen/xen_proc.h>
+#include <asm-xen/linux-public/privcmd.h>
#include <asm-xen/gnttab.h>
#ifndef set_fixmap_ma
#define ASSERT(_p) ((void)0)
#endif
+#define WPRINTK(fmt, args...) \
+ printk(KERN_WARNING "xen_grant: " fmt, ##args)
+
+
EXPORT_SYMBOL(gnttab_grant_foreign_access);
EXPORT_SYMBOL(gnttab_end_foreign_access);
+EXPORT_SYMBOL(gnttab_query_foreign_access);
EXPORT_SYMBOL(gnttab_grant_foreign_transfer);
EXPORT_SYMBOL(gnttab_end_foreign_transfer);
static grant_entry_t *shared;
+/* /proc/xen/grant */
+static struct proc_dir_entry *grant_pde;
+
+
/*
* Lock-free grant-entry allocator
*/
return ref;
}
+int
+gnttab_query_foreign_access( grant_ref_t ref )
+{
+ u16 nflags;
+
+ nflags = shared[ref].flags;
+
+ return ( nflags & (GTF_reading|GTF_writing) );
+}
+
void
-gnttab_end_foreign_access(
- grant_ref_t ref, int readonly)
+gnttab_end_foreign_access( grant_ref_t ref, int readonly )
{
u16 flags, nflags;
return frame;
}
-void __init gnttab_init(void)
+static int grant_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long data)
+{
+ int ret;
+ privcmd_hypercall_t hypercall;
+
+ if ( cmd != IOCTL_PRIVCMD_HYPERCALL )
+ return -ENOSYS;
+
+ if ( copy_from_user(&hypercall, (void *)data, sizeof(hypercall)) )
+ return -EFAULT;
+
+ if ( hypercall.op != __HYPERVISOR_grant_table_op )
+ return -ENOSYS;
+
+ /* hypercall-invoking asm taken from privcmd.c */
+ __asm__ __volatile__ (
+ "pushl %%ebx; pushl %%ecx; pushl %%edx; pushl %%esi; pushl %%edi; "
+ "movl 4(%%eax),%%ebx ;"
+ "movl 8(%%eax),%%ecx ;"
+ "movl 12(%%eax),%%edx ;"
+ "movl 16(%%eax),%%esi ;"
+ "movl 20(%%eax),%%edi ;"
+ "movl (%%eax),%%eax ;"
+ TRAP_INSTR "; "
+ "popl %%edi; popl %%esi; popl %%edx; popl %%ecx; popl %%ebx"
+ : "=a" (ret) : "0" (&hypercall) : "memory" );
+
+ return ret;
+}
+
+static struct file_operations grant_file_ops = {
+ ioctl: grant_ioctl,
+};
+
+static int grant_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len;
+ unsigned int i;
+ grant_entry_t *gt;
+
+ gt = (grant_entry_t *)shared;
+ len = 0;
+
+ for ( i = 0; i < NR_GRANT_REFS; i++ )
+ if ( gt[i].flags )
+ len += sprintf( page + len,
+ "Grant: ref (0x%x) flags (0x%hx) dom (0x%hx) frame (0x%x)\n",
+ i,
+ gt[i].flags,
+ gt[i].domid,
+ gt[i].frame );
+
+ *eof = 1;
+ return len;
+}
+
+static int grant_write(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ /* TODO: implement this */
+ return -ENOSYS;
+}
+
+static int __init gnttab_init(void)
{
gnttab_setup_table_t setup;
unsigned long frame;
set_fixmap_ma(FIX_GNTTAB, frame << PAGE_SHIFT);
shared = (grant_entry_t *)fix_to_virt(FIX_GNTTAB);
+
+ /*
+ * /proc/xen/grant : used by libxc to access grant tables
+ */
+ if ( (grant_pde = create_xen_proc_entry("grant", 0600)) == NULL )
+ {
+ WPRINTK("Unable to create grant xen proc entry\n");
+ return -1;
+ }
+
+ grant_file_ops.read = grant_pde->proc_fops->read;
+ grant_file_ops.write = grant_pde->proc_fops->write;
+
+ grant_pde->proc_fops = &grant_file_ops;
+
+ grant_pde->read_proc = &grant_read;
+ grant_pde->write_proc = &grant_write;
+
+ return 0;
}
+
+__initcall(gnttab_init);
gnttab_end_foreign_transfer(
grant_ref_t ref);
+int
+gnttab_query_foreign_access(
+ grant_ref_t ref );
+
#endif /* __ASM_GNTTAB_H__ */
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3)
- : "0" (__HYPERVISOR_grant_table_op), "1" (cmd), "2" (count), "3" (uop)
+ : "0" (__HYPERVISOR_grant_table_op), "1" (cmd), "2" (uop), "3" (count)
: "memory" );
return ret;
SRCS += xc_bvtsched.c
SRCS += xc_domain.c
SRCS += xc_evtchn.c
+SRCS += xc_gnttab.c
SRCS += xc_io.c
SRCS += xc_linux_build.c
SRCS += xc_plan9_build.c
int xc_get_pfn_list(int xc_handle, u32 domid, unsigned long *pfn_buf,
unsigned long max_pfns);
+/*\
+ * GRANT TABLE FUNCTIONS
+\*/
+
+/**
+ * This function opens a handle to the more restricted grant table hypervisor
+ * interface. This may be used where the standard interface is not
+ * available because the domain is not privileged.
+ * This function can be called multiple times within a single process.
+ * Multiple processes can have an open hypervisor interface at the same time.
+ *
+ * Each call to this function should have a corresponding call to
+ * xc_grant_interface_close().
+ *
+ * This function can fail if a Xen-enabled kernel is not currently running.
+ *
+ * @return a handle to the hypervisor grant table interface or -1 on failure
+ */
+int xc_grant_interface_open(void);
+
+/**
+ * This function closes an open grant table hypervisor interface.
+ *
+ * This function can fail if the handle does not represent an open interface or
+ * if there were problems closing the interface.
+ *
+ * @parm xc_handle a handle to an open grant table hypervisor interface
+ * @return 0 on success, -1 otherwise.
+ */
+int xc_grant_interface_close(int xc_handle);
+
+int xc_gnttab_map_grant_ref(int xc_handle,
+ memory_t host_virt_addr,
+ u32 dom,
+ u16 ref,
+ u16 flags,
+ s16 *handle,
+ memory_t *dev_bus_addr);
+
+int xc_gnttab_unmap_grant_ref(int xc_handle,
+ memory_t host_virt_addr,
+ memory_t dev_bus_addr,
+ u16 handle,
+ s16 *status);
+
+int xc_gnttab_setup_table(int xc_handle,
+ u32 dom,
+ u16 nr_frames,
+ s16 *status,
+ memory_t **frame_list);
+
+/* Grant debug builds only: */
+int xc_gnttab_dump_table(int xc_handle,
+ u32 dom,
+ s16 *status);
+
+
#endif /* __XC_H__ */
--- /dev/null
+/******************************************************************************
+ * xc_gnttab.c
+ *
+ * API for manipulating and accessing grant tables
+ *
+ * Copyright (c) 2005 Christopher Clark
+ * based on xc_evtchn.c Copyright (c) 2004, K A Fraser.
+ */
+
+#include "xc_private.h"
+#include "xen/grant_table.h"
+
+static int
+do_gnttab_op( int xc_handle,
+ unsigned long cmd,
+ gnttab_op_t *op,
+ unsigned long count )
+{
+ int ret = -1;
+ privcmd_hypercall_t hypercall;
+
+ hypercall.op = __HYPERVISOR_grant_table_op;
+ hypercall.arg[0] = cmd;
+ hypercall.arg[1] = (unsigned long)(op);
+ hypercall.arg[2] = count;
+
+ if ( mlock(op, sizeof(*op)) != 0 )
+ {
+ PERROR("Could not lock memory for Xen hypercall");
+ goto out1;
+ }
+
+ if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 )
+ {
+ printf("do_gnttab_op: hypercall returned error %d\n", ret);
+ goto out2;
+ }
+
+ out2: (void)munlock(op, sizeof(*op));
+ out1: return ret;
+}
+
+
+int xc_gnttab_map_grant_ref(int xc_handle,
+ memory_t host_virt_addr,
+ u32 dom,
+ u16 ref,
+ u16 flags,
+ s16 *handle,
+ memory_t *dev_bus_addr)
+{
+ gnttab_op_t op;
+ int rc;
+
+ op.u.map_grant_ref.host_virt_addr = host_virt_addr;
+ op.u.map_grant_ref.dom = (domid_t)dom;
+ op.u.map_grant_ref.ref = ref;
+ op.u.map_grant_ref.flags = flags;
+
+ if ( (rc = do_gnttab_op(xc_handle, GNTTABOP_map_grant_ref, &op, 1)) == 0 )
+ {
+ *handle = op.u.map_grant_ref.handle;
+ *dev_bus_addr = op.u.map_grant_ref.dev_bus_addr;
+ }
+
+ return rc;
+}
+
+
+int xc_gnttab_unmap_grant_ref(int xc_handle,
+ memory_t host_virt_addr,
+ memory_t dev_bus_addr,
+ u16 handle,
+ s16 *status)
+{
+ gnttab_op_t op;
+ int rc;
+
+ op.u.unmap_grant_ref.host_virt_addr = host_virt_addr;
+ op.u.unmap_grant_ref.dev_bus_addr = dev_bus_addr;
+ op.u.unmap_grant_ref.handle = handle;
+
+ if ( (rc = do_gnttab_op(xc_handle, GNTTABOP_unmap_grant_ref, &op, 1)) == 0 )
+ *status = op.u.unmap_grant_ref.status;
+
+ return rc;
+}
+
+int xc_gnttab_setup_table(int xc_handle,
+ u32 dom,
+ u16 nr_frames,
+ s16 *status,
+ memory_t **frame_list)
+{
+ gnttab_op_t op;
+ int rc;
+ int i;
+
+ op.u.setup_table.dom = (domid_t)dom;
+ op.u.setup_table.nr_frames = nr_frames;
+
+ if ( (rc = do_gnttab_op(xc_handle, GNTTABOP_setup_table, &op, 1)) == 0 )
+ {
+ *status = op.u.setup_table.status;
+ for ( i = 0; i < nr_frames; i++ )
+ {
+ (*frame_list)[i] = op.u.setup_table.frame_list[i];
+ }
+ }
+
+ return rc;
+}
+
+int xc_gnttab_dump_table(int xc_handle,
+ u32 dom,
+ s16 *status)
+{
+ gnttab_op_t op;
+ int rc;
+
+ op.u.dump_table.dom = (domid_t)dom;
+
+ printf("xc_gnttab_dump_table: domain %d\n", dom);
+
+ if ( (rc = do_gnttab_op(xc_handle, GNTTABOP_dump_table, &op, 1)) == 0 )
+ *status = op.u.dump_table.status;
+
+ return rc;
+}
+
+int xc_grant_interface_open(void)
+{
+ int fd = open("/proc/xen/grant", O_RDWR);
+ if ( fd == -1 )
+ PERROR("Could not obtain handle on grant command interface");
+ return fd;
+
+}
+
+int xc_grant_interface_close(int xc_grant_handle)
+{
+ return close(xc_grant_handle);
+}
{
int eax, ecx;
- __asm__ __volatile__ ("cpuid"
+ __asm__ __volatile__ ("pushl %%ebx; cpuid; popl %%ebx"
: "=a" (eax), "=c" (ecx)
: "0" (1)
- : "bx", "dx");
+ : "dx");
if (!(ecx & VMX_FEATURE_FLAG)) {
return -1;
}
(void)__put_user(GNTST_no_device_space, &uop->handle);
return;
}
+ DPRINTK("Mapping grant ref (%hu) for domain (%hu) with flags (%x)\n",
+ ref, dom, flags);
act = &rd->grant_table->active[ref];
sha = &rd->grant_table->shared[ref];
(void)__put_user(GNTST_bad_domain, &uop->status);
return;
}
+ DPRINTK("Unmapping grant ref (%hu) for domain (%hu) with handle (%hu)\n",
+ ref, dom, handle);
act = &rd->grant_table->active[ref];
sha = &rd->grant_table->shared[ref];
{
ASSERT(d->grant_table != NULL);
(void)put_user(GNTST_okay, &uop->status);
- (void)put_user(virt_to_phys(d->grant_table) >> PAGE_SHIFT,
+ (void)put_user(virt_to_phys(d->grant_table->shared) >> PAGE_SHIFT,
&uop->frame_list[0]);
}
return 0;
}
+#ifdef GRANT_DEBUG
+static int
+gnttab_dump_table(gnttab_dump_table_t *uop)
+{
+ grant_table_t *gt;
+ gnttab_dump_table_t op;
+ struct domain *d;
+ u32 shared_mfn;
+ active_grant_entry_t *act;
+ grant_entry_t sha_copy;
+ grant_mapping_t *maptrack;
+ int i;
+
+
+ if ( unlikely(copy_from_user(&op, uop, sizeof(op)) != 0) )
+ {
+ DPRINTK("Fault while reading gnttab_dump_table_t.\n");
+ return -EFAULT;
+ }
+
+ if ( op.dom == DOMID_SELF )
+ {
+ op.dom = current->domain->id;
+ }
+
+ if ( unlikely((d = find_domain_by_id(op.dom)) == NULL) )
+ {
+ DPRINTK("Bad domid %d.\n", op.dom);
+ (void)put_user(GNTST_bad_domain, &uop->status);
+ return 0;
+ }
+
+ ASSERT(d->grant_table != NULL);
+ gt = d->grant_table;
+ (void)put_user(GNTST_okay, &uop->status);
+
+ shared_mfn = virt_to_phys(d->grant_table->shared);
+
+ DPRINTK("Grant table for dom (%hu) MFN (%x)\n",
+ op.dom, shared_mfn);
+
+ spin_lock(>->lock);
+
+ ASSERT(d->grant_table->active != NULL);
+ ASSERT(d->grant_table->shared != NULL);
+
+ for ( i = 0; i < NR_GRANT_ENTRIES; i++ )
+ {
+ act = >->active[i];
+ sha_copy = gt->shared[i];
+
+ if ( act->pin || act->domid || act->frame ||
+ sha_copy.flags || sha_copy.domid || sha_copy.frame )
+ {
+ DPRINTK("Grant: dom (%hu) ACTIVE (%d) pin:(%x) dom:(%hu) frame:(%u)\n",
+ op.dom, i, act->pin, act->domid, act->frame);
+ DPRINTK("Grant: dom (%hu) SHARED (%d) flags:(%hx) dom:(%hu) frame:(%u)\n",
+ op.dom, i, sha_copy.flags, sha_copy.domid, sha_copy.frame);
+
+ }
+
+ }
+
+ ASSERT(d->grant_table->maptrack != NULL);
+
+ for ( i = 0; i < NR_MAPTRACK_ENTRIES; i++ )
+ {
+ maptrack = >->maptrack[i];
+
+ if ( maptrack->ref_and_flags & MAPTRACK_GNTMAP_MASK )
+ {
+ DPRINTK("Grant: dom (%hu) MAP (%d) ref:(%hu) flags:(%x) dom:(%hu)\n",
+ op.dom, i,
+ maptrack->ref_and_flags >> MAPTRACK_REF_SHIFT,
+ maptrack->ref_and_flags & MAPTRACK_GNTMAP_MASK,
+ maptrack->domid);
+ }
+ }
+
+ spin_unlock(>->lock);
+
+ put_domain(d);
+ return 0;
+}
+#endif
+
long
do_grant_table_op(
unsigned int cmd, void *uop, unsigned int count)
{
long rc;
- /* XXX stubbed out XXX */
- return -ENOSYS;
+ DPRINTK("Grant: table operation (%u) count: (%u)\n", cmd, count);
if ( count > 512 )
return -EINVAL;
case GNTTABOP_setup_table:
rc = gnttab_setup_table((gnttab_setup_table_t *)uop, count);
break;
+#ifdef GRANT_DEBUG
+ case GNTTABOP_dump_table:
+ rc = gnttab_dump_table((gnttab_dump_table_t *)uop);
+ break;
+#endif
default:
rc = -ENOSYS;
break;
return -ENOMEM;
}
+static void
+gnttab_release_all_mappings(grant_table_t *gt)
+{
+ grant_mapping_t *map;
+ domid_t dom;
+ grant_ref_t ref;
+ u16 handle, i;
+ struct domain *ld, *rd;
+ unsigned long frame;
+ active_grant_entry_t *act;
+ grant_entry_t *sha;
+
+ ld = current->domain;
+
+ for ( handle = 0; handle < NR_MAPTRACK_ENTRIES; handle++ )
+ {
+ map = >->maptrack[handle];
+
+ if ( map->ref_and_flags & MAPTRACK_GNTMAP_MASK )
+ {
+ dom = map->domid;
+ ref = map->ref_and_flags >> MAPTRACK_REF_SHIFT;
+
+ DPRINTK("Grant release (%hu) ref:(%hu) flags:(%x) dom:(%hu)\n",
+ handle, ref,
+ map->ref_and_flags & MAPTRACK_GNTMAP_MASK, dom);
+
+ if ( unlikely((rd = find_domain_by_id(dom)) == NULL) ||
+ unlikely(ld == rd) )
+ {
+ if ( rd != NULL )
+ put_domain(rd);
+ /* TODO: need to be able to handle domains destroyed
+ * with active mappings.
+ */
+ DPRINTK("Grant release: Could not find domain %d\n", dom);
+ continue;
+ }
+
+ act = &rd->grant_table->active[ref];
+ sha = &rd->grant_table->shared[ref];
+
+ spin_lock(&rd->grant_table->lock);
+
+ frame = act->frame;
+
+ for ( i = ((act->pin & GNTPIN_hstw_mask) >> GNTPIN_hstw_shift) +
+ ((act->pin & GNTPIN_devw_mask) >> GNTPIN_devw_shift);
+ i > 0; i-- )
+ {
+ put_page_type(&frame_table[frame]);
+ }
+ act->pin = 0;
+
+ put_page(&frame_table[frame]);
+
+ clear_bit(_GTF_reading, &sha->flags);
+ clear_bit(_GTF_writing, &sha->flags);
+
+ spin_unlock(&rd->grant_table->lock);
+
+ put_domain(rd);
+ }
+ }
+}
+
void
grant_table_destroy(
struct domain *d)
if ( (t = d->grant_table) != NULL )
{
+ if ( t->maptrack != NULL )
+ gnttab_release_all_mappings(t);
+
/* Free memory relating to this grant table. */
d->grant_table = NULL;
free_xenheap_page((unsigned long)t->shared);
void)
{
/* Nothing. */
+ DPRINTK("Grant table init\n");
}
/*
MEMORY_PADDING;
} PACKED gnttab_setup_table_t; /* 16 bytes */
+/*
+ * GNTTABOP_dump_table: Dump the contents of the grant table to the
+ * xen console. Debugging use only.
+ */
+#define GNTTABOP_dump_table 3
+typedef struct {
+ /* IN parameters. */
+ domid_t dom; /* 0 */
+ /* OUT parameters. */
+ s16 status; /* 2: GNTST_* */
+} PACKED gnttab_dump_table_t; /* 4 bytes */
+
+
/*
* Bitfield values for update_pin_status.flags.
*/
"permission denied" \
}
+
+typedef struct {
+ union { /* 0 */
+ gnttab_map_grant_ref_t map_grant_ref;
+ gnttab_unmap_grant_ref_t unmap_grant_ref;
+ gnttab_setup_table_t setup_table;
+ gnttab_dump_table_t dump_table;
+ u8 __dummy[24];
+ } PACKED u;
+} PACKED gnttab_op_t; /* 32 bytes */
#endif /* __XEN_PUBLIC_GRANT_TABLE_H__ */
#include <xen/config.h>
#include <public/grant_table.h>
+#define GRANT_DEBUG 1
+
/* Active grant entry - used for shadowing GTF_permit_access grants. */
typedef struct {
u32 pin; /* Reference count information. */